/*
 * Copyright (C) 2013 tangzhi
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.tangzsoft.pdmviewer.parser;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.ProcessingInstruction;
import org.dom4j.io.SAXReader;
import org.tangzsoft.pdmviewer.MainView;
import org.tangzsoft.pdmviewer.PdmViewerContext;
import org.tangzsoft.pdmviewer.model.PdmFile;
import org.tangzsoft.pdmviewer.model.PdmObject;
import org.tangzsoft.pdmviewer.model.PdmObjectRel;
import org.tangzsoft.pdmviewer.storage.Storage;
import org.tangzsoft.pdmviewer.utils.CaseInsensitiveMap;
import org.tangzsoft.pdmviewer.utils.Utils;

/**
 *
 * @author tangzhi
 */
public final class PdmParser {
    
    private MainView mainView;
    
    private Storage storage = PdmViewerContext.getInstance().getStorage();
    
    /**
     * 记录最近的对象的id
     */
    private static Map recentlyObjects = new HashMap<String, String>();
    
    /**
     * 文件ID
     */
    private String fileId;
    
    public PdmParser(MainView view) {
        mainView = view;
    }
    
    /**
     * 解析节点
     * @param element 
     */
    private void parserElement(Element element) {
        
        final String ns = element.getNamespacePrefix();
        
        final String name = element.getName();
        
        //非指定元素不解析
        if (!Constants.PARSER_ELEMENT.contains(name)) {
            return;
        }
        
        
        //attribute
        if (Constants.ATTRIBUTE_NAMESPACE.equals(ns)) {
            //永远走不进来
            throw new RuntimeException("name:"+name) ;
        }
        
        //collection
        if (Constants.COLLECTION_NAMESPACE.equals(ns)) {
            Iterator it = element.elementIterator();

            while(it.hasNext()) {
                parserElement((Element) it.next());
            }
        }
        
        //object
        if (Constants.OBJECTS_NAMESPACE.equals(ns)) {
            
            //针对Object的默认处理:记录其下的默认属性  
            //Id, Name, Code, CreationDate, Creator, ModificationDate, Modifier, Comment, Description
            String id = element.attributeValue(Constants.ID);
            
            //被引用对象，不再解析
            if (id == null) {
                return;
            }
            
            //记录最近一个对象的id
            recentlyObjects.put(name, id);
            
            //定义一个属性收集器
            Map attrs = new CaseInsensitiveMap<String>();
            
            Element child; String childName, childNS;
            
            Iterator it = element.elementIterator();
            
            while(it.hasNext()) {
                
                child = (Element) it.next();
                
                childName = child.getName();
                childNS = child.getNamespacePrefix();
                
                
                //attribute
                if (Constants.ATTRIBUTE_NAMESPACE.equals(childNS)) {
                    attrs.put(childName, child.getText());
                }
                
                //collection
                if (Constants.COLLECTION_NAMESPACE.equals(childNS)) {
                    parserElement(child);
                }
                
                //no object
                
            }
            
            //记录Object及其属性
            storage.getPdmObjectDAO().create(fileId, name, id, attrs);
            
            
            //Special Object Rel Deal
            dealSpecObjRel(fileId, name, id, element, recentlyObjects);
            
        }
        
    }
    
    
    /**
     * 解析pdm文件
     * @param pdmFile
     * @return 解析成功返回PdmFile对象，否则返回null
     * @throws Exception 
     */
    public PdmFile parserFile(File pdmFile) throws Exception {
        
        SAXReader saxReader = new SAXReader();

        Map map = new HashMap();
        map.put("a", "attribute");
        map.put("c", "collection");
        map.put("o", "object");

        saxReader.getDocumentFactory().setXPathNamespaceURIs(map);

        Document document = saxReader.read(pdmFile);

        ProcessingInstruction pi = document.processingInstruction("PowerDesigner");
        boolean ver=false;
        if (pi==null || Utils.isEmpty(pi.getValue("version")) 
            || (ver=true && Integer.valueOf(pi.getValue("version").substring(0, pi.getValue("version").indexOf(".")))<12)) {
            throw new Exception(ver?("文件版本低于V12.5.当前版本:"+pi.getValue("version")):"文件格式不正确");
        }

        Map fileAttrs = new CaseInsensitiveMap(pi.getValues());
        fileAttrs.put("Path", pdmFile.getAbsolutePath());
        fileAttrs.put("State", PdmFile.STATE_OPEN);
        
        //创建存储
        PdmFile pdm = storage.getPdmFileDAO().create(fileAttrs);
        fileId = pdm.getId();
        

        System.out.println("cur:"+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date((long)1102597831*1000)) );

        List list = document.selectNodes("/Model/o:RootObject/c:Children/o:Model");

        Iterator itModel=list.iterator();

        while(itModel.hasNext()) {

            final Element element = (Element) itModel.next();

            parserElement(element);

        }
        
        
        return pdm;
    }

    /**
     * 针对地处理某些对象之间关系
     * @param fileId
     * @param name
     * @param id
     * @param element
     * @param recentlyObjects 
     */
    private void dealSpecObjRel(String fileId, String name, String id, Element element, Map<String,String> recentlyObjects) {
        String[] types = new String[]{
            PdmObject.OBJECT_TYPE_DIAGRAM, /*处理PhysicalDiagram包含哪些对象*/
            PdmObject.OBJECT_TYPE_COLUMN,          /*处理Column的归属*/
            PdmObject.OBJECT_TYPE_KEY,             /*1.Key的归属; 2.Key包含的列*/
            PdmObject.OBJECT_TYPE_INDEX,           /*1.Index的归属; 2.Index包含的列*/
            PdmObject.OBJECT_TYPE_TABLE            /*1.Table包含的主键； 2.主键对应的Key*/
        };
        
        Set<String> specTypes = new HashSet<String>(Arrays.asList(types));
        
        if (!specTypes.contains(name)) {
            return;
        }
        
        if (PdmObject.OBJECT_TYPE_DIAGRAM.equals(name)) { //PhysicalDiagram
            
            //记录该节点下包含的表
            
            List list = element.selectNodes("c:Symbols/o:TableSymbol");
            Iterator itTs=list.iterator();

            while(itTs.hasNext()) {

                final Element tableSymbol = (Element) itTs.next();
                
                Attribute node = (Attribute) tableSymbol.selectSingleNode("c:Object/o:Table/@Ref");
                
                String tableId = node.getValue();
                
                storage.getPdmObjectRelDAO().create(PdmObjectRel.RelType.DIAGRAM_TABLE, fileId, id, tableId);
            }
        }else if (PdmObject.OBJECT_TYPE_COLUMN.equals(name)) { /*处理Column的归属*/
            
            String tabId = recentlyObjects.get(PdmObject.OBJECT_TYPE_TABLE);
            storage.getPdmObjectRelDAO().create(PdmObjectRel.RelType.TABLE_COLUMN, fileId, tabId, id);
            
        }else if (PdmObject.OBJECT_TYPE_KEY.equals(name)) {
            
            /*1.Key的归属; */
            String tabId = recentlyObjects.get(PdmObject.OBJECT_TYPE_TABLE);
            storage.getPdmObjectRelDAO().create(PdmObjectRel.RelType.TABLE_KEY, fileId, tabId, id);
            
            /*2.Key包含的列*/
            List list = element.selectNodes("c:Key.Columns/o:Column/@Ref");
            Iterator iter=list.iterator();
            
            String colId;
            while(iter.hasNext()){
                Attribute attribute=(Attribute)iter.next();
                colId = attribute.getValue();
                storage.getPdmObjectRelDAO().create(PdmObjectRel.RelType.KEY_COLUMN, fileId, id, colId);
            }
            
            
        }else if (PdmObject.OBJECT_TYPE_INDEX.equals(name)) {
            
            /*1.Index的归属;*/
            String tabId = recentlyObjects.get(PdmObject.OBJECT_TYPE_TABLE);
            storage.getPdmObjectRelDAO().create(PdmObjectRel.RelType.TABLE_INDEX, fileId, tabId, id);
            
            
            /* 2.Index包含的列*/
            List list = element.selectNodes("c:IndexColumns/o:IndexColumn/c:Column/o:Column/@Ref");
            Iterator iter=list.iterator();
            
            String colId;
            while(iter.hasNext()){
                Attribute attribute=(Attribute)iter.next();
                colId = attribute.getValue();
                storage.getPdmObjectRelDAO().create(PdmObjectRel.RelType.INDEX_COLUMN, fileId, id, colId);
            }
            
            
        }else if (PdmObject.OBJECT_TYPE_TABLE.equals(name)) {
            
            /*1.Table包含的主键；*/
            
            
            
            /* 2.主键对应的Key*/
            
            
        }
        
    }
    
}
